"""
Website Manager - Handle website profiles and configurations.

This module provides functionality for managing website-specific configurations,
including authentication patterns, browser settings, and custom automation scripts.
"""

import os
import json
import logging
from typing import Dict, List, Optional, Any, Set
from pathlib import Path
from urllib.parse import urlparse

from models import (
    WebsiteProfile, 
    AuthMethod, 
    BrowserConfig, 
    SessionConfig, 
    WebsiteSelectors,
    create_default_website_profile
)


class WebsiteManager:
    """
    Manages website profiles and configurations.
    
    Handles website-specific settings, validation, and provides
    a centralized interface for website profile operations.
    """
    
    def __init__(self, profiles_dir: str = "website_profiles"):
        """
        Initialize the Website Manager.
        
        Args:
            profiles_dir: Directory to store website profiles
        """
        self.profiles_dir = Path(profiles_dir)
        self.profiles_dir.mkdir(exist_ok=True)
        
        self.logger = self._setup_logging()
        self._profiles: Dict[str, WebsiteProfile] = {}
        
        # Load existing profiles
        self._load_profiles()
        
        # Built-in profile templates
        self._builtin_templates = self._create_builtin_templates()
        
        self.logger.info("WebsiteManager initialized")
    
    def _setup_logging(self) -> logging.Logger:
        """Setup logging configuration."""
        logger = logging.getLogger("WebsiteManager")
        logger.setLevel(logging.INFO)
        
        if not logger.handlers:
            handler = logging.StreamHandler()
            formatter = logging.Formatter(
                '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
            )
            handler.setFormatter(formatter)
            logger.addHandler(handler)
        
        return logger
    
    def _load_profiles(self):
        """Load website profiles from storage."""
        try:
            for profile_file in self.profiles_dir.glob("*.json"):
                with open(profile_file, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    profile = WebsiteProfile.from_dict(data)
                    self._profiles[profile.website_id] = profile
                    self.logger.debug(f"Loaded profile: {profile.website_id}")
        except Exception as e:
            self.logger.error(f"Failed to load profiles: {e}")
    
    def _save_profile(self, profile: WebsiteProfile):
        """Save profile to storage."""
        profile_file = self.profiles_dir / f"{profile.website_id}.json"
        try:
            with open(profile_file, 'w', encoding='utf-8') as f:
                json.dump(profile.to_dict(), f, indent=2, ensure_ascii=False)
            self.logger.debug(f"Saved profile: {profile.website_id}")
        except Exception as e:
            self.logger.error(f"Failed to save profile {profile.website_id}: {e}")
            raise
    
    def _create_builtin_templates(self) -> Dict[str, WebsiteProfile]:
        """Create built-in website profile templates."""
        templates = {}
        
        # GeekBI template (current default from config.py)
        templates["geekbi"] = WebsiteProfile(
            website_id="geekbi",
            display_name="极鲸云平台",
            target_url="https://www.geekbi.com",
            login_url="https://www.geekbi.com/login",
            auth_method=AuthMethod.MANUAL,
            selectors=WebsiteSelectors(
                username_field="#username",
                password_field="#password",
                submit_button=".login-btn"
            ),
            browser_config=BrowserConfig(
                viewport={"width": 1920, "height": 1080},
                extra_args=["--start-maximized"]
            ),
            session_config=SessionConfig(
                timeout_hours=24,
                backup_extensions=True
            )
        )
        
        # Seerfar template
        templates["seerfar"] = WebsiteProfile(
            website_id="seerfar",
            display_name="Seerfar Admin",
            target_url="https://seerfar.cn/admin/sign-in.html",
            auth_method=AuthMethod.MANUAL,
            session_config=SessionConfig(timeout_hours=12)
        )
        
        # Tabcut template 
        templates["tabcut"] = WebsiteProfile(
            website_id="tabcut",
            display_name="特看数据",
            target_url="https://www.tabcut.com/zh-CN/workbench",
            auth_method=AuthMethod.MANUAL,
            session_config=SessionConfig(timeout_hours=24)
        )
        
        # Menglar template
        templates["menglar"] = WebsiteProfile(
            website_id="menglar",
            display_name="萌啦数据",
            target_url="https://ozon.menglar.com/workbench/dashboard",
            auth_method=AuthMethod.MANUAL,
            session_config=SessionConfig(timeout_hours=24)
        )
        
        # FastMoss template
        templates["fastmoss"] = WebsiteProfile(
            website_id="fastmoss",
            display_name="FastMoss",
            target_url="https://www.fastmoss.com/zh",
            auth_method=AuthMethod.MANUAL,
            session_config=SessionConfig(timeout_hours=24)
        )
        
        return templates
    
    def validate_profile(self, profile: WebsiteProfile) -> List[str]:
        """
        Validate website profile configuration.
        
        Args:
            profile: Website profile to validate
            
        Returns:
            List of validation errors (empty if valid)
        """
        errors = []
        
        # Required field validation
        if not profile.website_id:
            errors.append("Website ID is required")
        elif not profile.website_id.replace('_', '').replace('-', '').isalnum():
            errors.append("Website ID must contain only letters, numbers, hyphens, and underscores")
        
        if not profile.display_name:
            errors.append("Display name is required")
        
        if not profile.target_url:
            errors.append("Target URL is required")
        else:
            # URL validation
            try:
                parsed = urlparse(profile.target_url)
                if not all([parsed.scheme, parsed.netloc]):
                    errors.append("Target URL must be a valid HTTP/HTTPS URL")
                elif parsed.scheme not in ['http', 'https']:
                    errors.append("Target URL must use HTTP or HTTPS protocol")
            except Exception:
                errors.append("Invalid target URL format")
        
        # Login URL validation (if provided)
        if profile.login_url:
            try:
                parsed = urlparse(profile.login_url)
                if not all([parsed.scheme, parsed.netloc]):
                    errors.append("Login URL must be a valid HTTP/HTTPS URL")
            except Exception:
                errors.append("Invalid login URL format")
        
        # Authentication method validation
        if profile.auth_method == AuthMethod.FORM:
            if not profile.selectors.username_field:
                errors.append("Username field selector required for form authentication")
            if not profile.selectors.password_field:
                errors.append("Password field selector required for form authentication")
        
        # Browser configuration validation
        if profile.browser_config.viewport:
            viewport = profile.browser_config.viewport
            if viewport.get("width", 0) < 800 or viewport.get("height", 0) < 600:
                errors.append("Browser viewport must be at least 800x600")
        
        # Session configuration validation
        if profile.session_config.timeout_hours < 1:
            errors.append("Session timeout must be at least 1 hour")
        elif profile.session_config.timeout_hours > 8760:  # 1 year
            errors.append("Session timeout cannot exceed 1 year")
        
        return errors
    
    def add_profile(self, profile: WebsiteProfile, overwrite: bool = False) -> bool:
        """
        Add a new website profile.
        
        Args:
            profile: Website profile to add
            overwrite: Whether to overwrite existing profile
            
        Returns:
            True if successful, False otherwise
        """
        try:
            # Validate profile
            errors = self.validate_profile(profile)
            if errors:
                self.logger.error(f"Profile validation failed: {errors}")
                return False
            
            # Check for existing profile
            if profile.website_id in self._profiles and not overwrite:
                self.logger.error(f"Profile already exists: {profile.website_id}")
                return False
            
            # Update timestamp
            profile.update_timestamp()
            
            # Save profile
            self._profiles[profile.website_id] = profile
            self._save_profile(profile)
            
            action = "Updated" if overwrite else "Added"
            self.logger.info(f"{action} website profile: {profile.website_id}")
            return True
            
        except Exception as e:
            self.logger.error(f"Failed to add profile: {e}")
            return False
    
    def update_profile(self, website_id: str, updates: Dict[str, Any]) -> bool:
        """
        Update an existing website profile.
        
        Args:
            website_id: Website identifier
            updates: Dictionary of fields to update
            
        Returns:
            True if successful, False otherwise
        """
        try:
            if website_id not in self._profiles:
                self.logger.error(f"Profile not found: {website_id}")
                return False
            
            profile = self._profiles[website_id]
            
            # Apply updates
            for field, value in updates.items():
                if field == "selectors" and isinstance(value, dict):
                    # Update selectors
                    current_selectors = profile.selectors.to_dict()
                    current_selectors.update(value)
                    profile.selectors = WebsiteSelectors.from_dict(current_selectors)
                elif field == "browser_config" and isinstance(value, dict):
                    # Update browser config
                    current_config = profile.browser_config.to_dict()
                    current_config.update(value)
                    profile.browser_config = BrowserConfig.from_dict(current_config)
                elif field == "session_config" and isinstance(value, dict):
                    # Update session config
                    current_config = profile.session_config.to_dict()
                    current_config.update(value)
                    profile.session_config = SessionConfig.from_dict(current_config)
                elif hasattr(profile, field):
                    setattr(profile, field, value)
                else:
                    self.logger.warning(f"Unknown field: {field}")
            
            # Validate updated profile
            errors = self.validate_profile(profile)
            if errors:
                self.logger.error(f"Updated profile validation failed: {errors}")
                return False
            
            # Update timestamp and save
            profile.update_timestamp()
            self._save_profile(profile)
            
            self.logger.info(f"Updated profile: {website_id}")
            return True
            
        except Exception as e:
            self.logger.error(f"Failed to update profile: {e}")
            return False
    
    def remove_profile(self, website_id: str) -> bool:
        """
        Remove a website profile.
        
        Args:
            website_id: Website identifier
            
        Returns:
            True if successful, False otherwise
        """
        try:
            if website_id not in self._profiles:
                self.logger.warning(f"Profile not found: {website_id}")
                return False
            
            # Remove from memory
            del self._profiles[website_id]
            
            # Remove file
            profile_file = self.profiles_dir / f"{website_id}.json"
            if profile_file.exists():
                profile_file.unlink()
            
            self.logger.info(f"Removed profile: {website_id}")
            return True
            
        except Exception as e:
            self.logger.error(f"Failed to remove profile: {e}")
            return False
    
    def get_profile(self, website_id: str) -> Optional[WebsiteProfile]:
        """
        Get website profile by ID.
        
        Args:
            website_id: Website identifier
            
        Returns:
            Website profile or None if not found
        """
        return self._profiles.get(website_id)
    
    def list_profiles(self, include_templates: bool = False) -> List[WebsiteProfile]:
        """
        Get all website profiles.
        
        Args:
            include_templates: Whether to include built-in templates
            
        Returns:
            List of website profiles
        """
        profiles = list(self._profiles.values())
        
        if include_templates:
            # Add templates that aren't already saved as profiles
            for template_id, template in self._builtin_templates.items():
                if template_id not in self._profiles:
                    profiles.append(template)
        
        return profiles
    
    def search_profiles(self, query: str) -> List[WebsiteProfile]:
        """
        Search profiles by name or URL.
        
        Args:
            query: Search query
            
        Returns:
            List of matching profiles
        """
        query_lower = query.lower()
        matches = []
        
        for profile in self._profiles.values():
            if (query_lower in profile.display_name.lower() or
                query_lower in profile.target_url.lower() or
                query_lower in profile.website_id.lower()):
                matches.append(profile)
        
        return matches
    
    def get_profile_by_url(self, url: str) -> Optional[WebsiteProfile]:
        """
        Find profile by target URL.
        
        Args:
            url: Target URL to match
            
        Returns:
            Matching profile or None
        """
        try:
            parsed_url = urlparse(url)
            target_domain = parsed_url.netloc.lower()
            
            for profile in self._profiles.values():
                profile_parsed = urlparse(profile.target_url)
                profile_domain = profile_parsed.netloc.lower()
                
                if target_domain == profile_domain:
                    return profile
                    
        except Exception as e:
            self.logger.error(f"Error matching URL: {e}")
        
        return None
    
    def create_from_template(self, template_id: str, website_id: str, 
                           display_name: str, target_url: str) -> Optional[WebsiteProfile]:
        """
        Create profile from built-in template.
        
        Args:
            template_id: Built-in template identifier
            website_id: New website identifier
            display_name: New display name
            target_url: New target URL
            
        Returns:
            Created profile or None if template not found
        """
        if template_id not in self._builtin_templates:
            self.logger.error(f"Template not found: {template_id}")
            return None
        
        template = self._builtin_templates[template_id]
        
        # Create new profile based on template
        new_profile = WebsiteProfile(
            website_id=website_id,
            display_name=display_name,
            target_url=target_url,
            login_url=template.login_url,
            auth_method=template.auth_method,
            selectors=template.selectors,
            custom_scripts=template.custom_scripts.copy(),
            browser_config=template.browser_config,
            session_config=template.session_config
        )
        
        return new_profile
    
    def export_profiles(self, export_path: str, profile_ids: Optional[List[str]] = None) -> bool:
        """
        Export profiles to JSON file.
        
        Args:
            export_path: Path to export file
            profile_ids: Specific profile IDs to export (None for all)
            
        Returns:
            True if successful, False otherwise
        """
        try:
            profiles_to_export = {}
            
            if profile_ids is None:
                # Export all profiles
                for profile_id, profile in self._profiles.items():
                    profiles_to_export[profile_id] = profile.to_dict()
            else:
                # Export specific profiles
                for profile_id in profile_ids:
                    if profile_id in self._profiles:
                        profiles_to_export[profile_id] = self._profiles[profile_id].to_dict()
            
            export_data = {
                "export_timestamp": str(datetime.now()),
                "profiles": profiles_to_export
            }
            
            with open(export_path, 'w', encoding='utf-8') as f:
                json.dump(export_data, f, indent=2, ensure_ascii=False)
            
            self.logger.info(f"Exported {len(profiles_to_export)} profiles to {export_path}")
            return True
            
        except Exception as e:
            self.logger.error(f"Failed to export profiles: {e}")
            return False
    
    def import_profiles(self, import_path: str, overwrite: bool = False) -> Dict[str, bool]:
        """
        Import profiles from JSON file.
        
        Args:
            import_path: Path to import file
            overwrite: Whether to overwrite existing profiles
            
        Returns:
            Dictionary with import results for each profile
        """
        results = {}
        
        try:
            with open(import_path, 'r', encoding='utf-8') as f:
                import_data = json.load(f)
            
            profiles_data = import_data.get("profiles", {})
            
            for profile_id, profile_data in profiles_data.items():
                try:
                    profile = WebsiteProfile.from_dict(profile_data)
                    success = self.add_profile(profile, overwrite=overwrite)
                    results[profile_id] = success
                    
                except Exception as e:
                    self.logger.error(f"Failed to import profile {profile_id}: {e}")
                    results[profile_id] = False
            
            successful_imports = sum(1 for success in results.values() if success)
            self.logger.info(f"Imported {successful_imports}/{len(results)} profiles")
            
        except Exception as e:
            self.logger.error(f"Failed to import profiles: {e}")
        
        return results
    
    def get_profile_statistics(self) -> Dict[str, Any]:
        """
        Get statistics about website profiles.
        
        Returns:
            Dictionary with profile statistics
        """
        total_profiles = len(self._profiles)
        auth_methods = {}
        domain_counts = {}
        
        for profile in self._profiles.values():
            # Count auth methods
            method = profile.auth_method.value
            auth_methods[method] = auth_methods.get(method, 0) + 1
            
            # Count domains
            try:
                domain = urlparse(profile.target_url).netloc
                domain_counts[domain] = domain_counts.get(domain, 0) + 1
            except Exception:
                pass
        
        return {
            "total_profiles": total_profiles,
            "auth_methods": auth_methods,
            "domains": domain_counts,
            "available_templates": list(self._builtin_templates.keys())
        }
    
    def list_templates(self) -> List[str]:
        """Get list of available built-in templates."""
        return list(self._builtin_templates.keys())
    
    def get_template(self, template_id: str) -> Optional[WebsiteProfile]:
        """Get built-in template by ID."""
        return self._builtin_templates.get(template_id)